﻿using System.Collections.Generic;
using System.Collections.Specialized;

namespace H.Daos
{
    public interface IAbstractQuery
    {
        /// <summary>
        /// 获取当前查询对象生成的SELECT SQL语句
        /// </summary>
        /// <returns></returns>
        string FetchSelectSQL(out KeyValuePair<string, object>[] valueBinding);

        /// <summary>
        /// 获取读取某列的SQL语句
        /// </summary>
        /// <param name="field">需要返回的值的字段</param>
        /// <param name="valueBinding">返回所有与SQL相关的占位符对应的值</param>
        /// <returns>返回生成的SQL语句</returns>
        string FetchColumnSQL(string field, out KeyValuePair<string, object>[] valueBinding);

        /// <summary>
        /// 获取读取某个值的SQL语句(无论结果多少行,只取第一个)
        /// </summary>
        /// <param name="field">需要返回的值的字段</param>
        /// <param name="valueBinding">返回所有与SQL相关的占位符对应的值</param>
        /// <returns>返回生成的SQL语句</returns>
        string FetchValueSQL(string field, out KeyValuePair<string, object>[] valueBinding);

        /// <summary>
        /// 获取一个更新语句
        /// </summary>
        /// <param name="values">希望更新的数据</param>
        /// <param name="valueBinding">返回所有与SQL相关的占位符对应的值</param>
        /// <returns>返回生成的SQL语句</returns>
        string FetchUpdateSQL(KeyValuePair<string, object>[] values, out KeyValuePair<string, object>[] valueBinding);

        /// <summary>
        /// 获取一个删除语句
        /// </summary>
        /// <param name="valueBinding">返回所有与SQL相关的占位符对应的值</param>
        /// <returns>返回生成的SQL语句</returns>
        string FetchDeleteSQL(out KeyValuePair<string, object>[] valueBinding);

        /// <summary>
        /// 从表中读取某一列
        /// </summary>
        /// <typeparam name="T">希望获取的值的类型</typeparam>
        /// <returns>值的列的类型</returns>
        T[] Column<T>(string field);

        /// <summary>
        /// 从表中读取一个值
        /// </summary>
        /// <typeparam name="T">希望获取的值的类型</typeparam>
        /// <returns>希望获取的值</returns>
        T Value<T>(string field);

        /// <summary>
        /// 删除查询到的数据
        /// </summary>
        /// <returns>返回受影响的条数</returns>
        int Delete();

        /// <summary>
        /// 更新查询到的数据
        /// </summary>
        /// <param name="values">新的值</param>
        /// <returns>返回受影响的条数</returns>
        int Update(KeyValuePair<string, object>[] values);

        /// <summary>
        /// 更新某一列的值
        /// </summary>
        /// <param name="column"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        int Update(string column, object value);
    }

    public interface IQuery : IAbstractQuery
    {
        /// <summary>
        /// 设置当前查询的数据库表
        /// </summary>
        /// <param name="tableName">当前查询的数据库表</param>
        /// <returns>返回当前查询对象,以便链式查询</returns>
        IQuery Table(string tableName);

        /// <summary>
        /// 增加查询条件,以AND方式追加
        /// </summary>
        /// <param name="field">需要被判断的字段</param>
        /// <param name="op">操作符</param>
        /// <param name="value">值</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery Where(string field, string op, object value);

        /// <summary>
        /// 增加查询条件,以OR方式追加
        /// </summary>
        /// <param name="field">需要被判断的字段</param>
        /// <param name="op">操作符</param>
        /// <param name="value">值</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery WhereOr(string field, string op, object value);

        /// <summary>
        /// 增加字段为NULL查询条件,以AND方式增加
        /// </summary>
        /// <param name="field">需要被判断的字段</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery WhereNull(string field);

        /// <summary>
        /// 增加字段为NULL查询条件,以AND方式增加
        /// </summary>
        /// <param name="field">需要被判断的字段</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery WhereNullOr(string field);

        /// <summary>
        /// 增加字段为NOT NULL查询条件,以OR方式增加
        /// </summary>
        /// <param name="field">需要被判断的字段</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery WhereNotNull(string field);

        /// <summary>
        /// 增加字段为NOT NULL查询条件,以OR方式增加
        /// </summary>
        /// <param name="field">需要被判断的字段</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery WhereNotNullOr(string field);

        /// <summary>
        /// 设置返回的排序方式
        /// </summary>
        /// <param name="field">需要被排序的字段</param>
        /// <param name="desc">是否将字段以降序排列</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery Order(string field, bool desc = false);

        /// <summary>
        /// 设置返回的排序方式
        /// </summary>
        /// <param name="fields">需要被排序的字段</param>
        /// <param name="desc">是否将字段以降序排列</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery Order(string[] fields, bool desc = false);

        /// <summary>
        /// 限制查询时返回的数据的条数
        /// </summary>
        /// <param name="limit">限制返回的条数</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery Limit(int limit);

        /// <summary>
        /// 限制查询时返回的数据的条数,并指定跳过多少条才开始截取
        /// </summary>
        /// <param name="limit">限制返回的条数</param>
        /// <param name="offset">跳过的条数</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery Limit(int limit, int offset);

        /// <summary>
        /// 返回指定的列
        /// </summary>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery Fields(params string[] fields);

        /// <summary>
        /// 指定返回某些字段并使结果唯一
        /// </summary>
        /// <param name="fields">需要返回的字段</param>
        /// <returns>返回值</returns>
        IQuery Distinct(params string[] fields);

        /// <summary>
        /// 返回所有查找到的模型
        /// </summary>
        /// <returns>开始执行Select语句</returns>
        NameValueCollection[] Select();

        /// <summary>
        /// 克隆当前查询对象
        /// </summary>
        /// <returns>返回克隆后的查询对象,新查询对象与本对象独立存在</returns>
        IQuery Clone();
    }

    /// <summary>
    /// 指定模型返回的查询接口
    /// </summary>
    /// <typeparam name="M"></typeparam>
    public interface IQuery<M> : IAbstractQuery where M : AbstractEntity
    {
        /// <summary>
        /// 设置当前查询的数据库表
        /// </summary>
        /// <param name="tableName">当前查询的数据库表</param>
        /// <returns>返回当前查询对象,以便链式查询</returns>
        IQuery<M> Table(string tableName);

        /// <summary>
        /// 增加查询条件,以AND方式追加
        /// </summary>
        /// <param name="field">需要被判断的字段</param>
        /// <param name="op">操作符</param>
        /// <param name="value">值</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery<M> Where(string field, string op, object value);

        /// <summary>
        /// 增加查询条件,以OR方式追加
        /// </summary>
        /// <param name="field">需要被判断的字段</param>
        /// <param name="op">操作符</param>
        /// <param name="value">值</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery<M> WhereOr(string field, string op, object value);

        /// <summary>
        /// 增加字段为NULL查询条件,以AND方式增加
        /// </summary>
        /// <param name="field">需要被判断的字段</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery<M> WhereNull(string field);

        /// <summary>
        /// 增加字段为NULL查询条件,以AND方式增加
        /// </summary>
        /// <param name="field">需要被判断的字段</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery<M> WhereNullOr(string field);

        /// <summary>
        /// 增加字段为NOT NULL查询条件,以OR方式增加
        /// </summary>
        /// <param name="field">需要被判断的字段</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery<M> WhereNotNull(string field);

        /// <summary>
        /// 增加字段为NOT NULL查询条件,以OR方式增加
        /// </summary>
        /// <param name="field">需要被判断的字段</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery<M> WhereNotNullOr(string field);

        /// <summary>
        /// 设置返回的排序方式
        /// </summary>
        /// <param name="field">需要进行排序的字段</param>
        /// <param name="desc">是否进行降序排列</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery<M> Order(string field, bool desc = false);

        /// <summary>
        /// 设置返回的排序方式
        /// </summary>
        /// <param name="fields">需要进行排序的字段</param>
        /// <param name="desc">是否进行降序排列</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery<M> Order(string[] fields, bool desc = false);

        /// <summary>
        /// 限制查询时返回的数据的条数
        /// </summary>
        /// <param name="limit">限制返回的条数</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery<M> Limit(int limit);

        /// <summary>
        /// 限制查询时返回的数据的条数,并指定跳过多少条才开始截取
        /// </summary>
        /// <param name="limit">限制返回的条数</param>
        /// <param name="offset">需要忽略的条数</param>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery<M> Limit(int limit, int offset);

        /// <summary>
        /// 返回指定的列
        /// </summary>
        /// <returns>返回当前对象,以便链式操作</returns>
        IQuery Fields(params string[] fields);

        /// <summary>
        /// 指定返回某些字段并使结果唯一
        /// </summary>
        /// <param name="fields">需要返回的字段</param>
        /// <returns>返回值</returns>
        IQuery Distinct(params string[] fields);

        /// <summary>
        /// 开始执行查询语句
        /// </summary>
        /// <returns></returns>
        M[] Select();

        /// <summary>
        /// 克隆当前查询对象
        /// </summary>
        /// <returns>返回克隆后的查询对象,新查询对象与本对象独立存在</returns>
        IQuery<M> Clone();
    }
}
